package parsetree;

import java.util.Comparator;
import java.util.List;

import javax.swing.text.AbstractDocument.ElementEdit;

import com.google.common.collect.ImmutableList;

public interface BranchElement extends Element {
    
    ElementEdit addChild(Element elem);
    
    
    Element getChildContaining(int documentOffset);
    
    
    Element getChildStartsWith(int documentOffset);
    
    
    Element getChildEndsWith(int documentOffset);
    
    @Override
    int getChildCount();
    
    @Override
    boolean hasChildren();
    
    /**
     * This method returns the index within the internal list of the object that contains
     * the supplied modelOffset for the index that starts with or ends with a given offset
     * see {@link #getIndexOfChildStartsWith(int)} and {@link #getIndexOfChildEndsWith(int)}
     * respectively. If no child contains the supplied index, the return value will relate
     * to the location the child woul have been, in the manner of a
     * {@link java.util.Collections#binarySearch(List, Object, Comparator) binarySearch}
     * @param documentOffset the offset within the document model of the child to access
     * @return an index position within the Element to access the Child
     * @see {@link #getIndexOfChildStartsWith(int)}<br>{@link #getIndexOfChildEndsWith(int)}<br>
     * {@link java.util.Collections#binarySearch(List, Object, Comparator)}
     */
    int getIndexOfChildContaining(int documentOffset);
    
    /**
     * Adds a sorted continuous array of elements to the children of this Element. Since the child list must be kept
     * in sorted order, the index of the element will be automatically derived from the
     * child's getStartOffset() and getEndOffset() methods. If those two methods do not
     * provide a valid modelOffset the child will simply be inserted at the end of the
     * list, which could unpredictable behavior and should not be used.
     * @param elem the element which will be a child of the current element
     * @return true if a position could be derived, false if the element was inserted at
     *         the end of the child list.
     */
    ElementEdit addChildren(Element[] elems, boolean mergeLeft, boolean mergeRight);
    
    /**
     * Removes the a given child from this iff the child's
     * {@link Element#getStartOffset() startOffset} == its
     * {@link Element#getEndOffset() endOffset}
     * @param elem the element to be removed if it's empty
     * @return A {@link ElementEdit} describing the change that resulted from
     * the method-call, or null if elem was not empty, or not a child of this  
     */
    public ElementEdit removeEmptyChild(Element elem);
    
    
    public abstract int getIndexOfChildEndsWith(int documentOffset);
    
    
    public abstract int getIndexOfChildStartsWith(int documentOffset);
    
    
    public abstract ImmutableList<Element> getChildren();
    
}